package com.jch.dm3_two_phase_termination.reusable_code;

public abstract class AbstractTerminatableThread extends Thread implements Terminatable {

    private final boolean DEBUG = true;

    public final TerminationToken terminationToken;

    public AbstractTerminatableThread() {
        this(new TerminationToken());
    }

    /**
     * @param terminationToken 线程间共享的线程终止标志实例
     */
    public AbstractTerminatableThread(TerminationToken terminationToken) {
        this.terminationToken = terminationToken;
        terminationToken.register(this);
    }

    /**
     * 线程处理逻辑
     *
     * @throws Exception
     */
    protected abstract void doRun() throws Exception;

    /**
     * 用于实现线程停止后的一些清理动作
     *
     * @param cause
     */
    protected void doCleanup(Exception cause) {
        // 什么也不做，子类依据具体业务实现
    }

    /**
     * 用于执行线程停止所需的操作
     */
    protected void doTerminate() {
        // 子类依据具体业务实现
    }

    @Override
    public void run() {
        Exception ex = null;
        try {
            for (; ; ) {
                // 执行线程的处理逻辑前先判断线程停止的标志
                if (terminationToken.isToShutdown() && terminationToken.reservations.get() <= 0) {
                    break;
                }
                doRun();
            }
        } catch (Exception e) {
            // 使得线程能够响应interrupt调用而退出
            ex = e;
            if (e instanceof InterruptedException) {
                if (DEBUG) {
                    e.printStackTrace();
                }
            } else {
                System.err.println(e.getLocalizedMessage());
            }
        } finally {
            try {
                doCleanup(ex);
            } finally {
                terminationToken.notifyThreadTermination(this);
            }
        }
    }

    // 打断线程
    @Override
    public void interrupt() {
        terminate();
    }

    // 请求停止线程
    @Override
    public void terminate() {
        terminationToken.setToShutdown(true);
        try {
            doTerminate();
        } finally {
            // 若无待处理的任务，则试图强制终止线程
            if (terminationToken.reservations.get() <= 0){
                super.interrupt();
            }
        }
    }

    public void terminate(boolean waitUtilThreadTerminated){
        terminate();
        if (waitUtilThreadTerminated){
            try {
                this.join();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}
